home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1997 April / EnigmA AMIGA RUN 17 (1997)(G.R. Edizioni)(IT)[!][issue 1997-04][EAR-CD].iso / EARCD / text / hyper / hsc_source.lha / hsc / source / hsclib / parse.c < prev    next >
C/C++ Source or Header  |  1996-12-04  |  31KB  |  1,132 lines

  1. /*
  2.  * hsclib/parse.c
  3.  *
  4.  * parse file: handle for entities & tags
  5.  *
  6.  * Copyright (C) 1995,96  Thomas Aglassinger
  7.  *
  8.  * This program is free software; you can redistribute it and/or modify
  9.  * it under the terms of the GNU General Public License as published by
  10.  * the Free Software Foundation; either version 2 of the License, or
  11.  * (at your option) any later version.
  12.  *
  13.  * This program is distributed in the hope that it will be useful,
  14.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16.  * GNU General Public License for more details.
  17.  *
  18.  * You should have received a copy of the GNU General Public License
  19.  * along with this program; if not, write to the Free Software
  20.  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  21.  *
  22.  * updated: 22-Nov-1996
  23.  * created:  1-Jul-1995
  24.  *
  25.  */
  26.  
  27. #define NOEXTERN_HSCLIB_PARSE_H
  28.  
  29. #include "hsclib/inc_base.h"
  30.  
  31. #include "hsclib/defattr.h"
  32. #include "hsclib/deftag.h"
  33. #include "hsclib/idref.h"
  34. #include "hsclib/include.h"
  35. #include "hsclib/input.h"
  36. #include "hsclib/parse.h"
  37. #include "hsclib/posteval.h"
  38. #include "hscprj/project.h"
  39. #include "hsclib/skip.h"
  40. #include "hsclib/size.h"
  41. #include "hsclib/uri.h"
  42.  
  43. /*
  44.  *---------------------------
  45.  * misc. functions
  46.  *---------------------------
  47.  */
  48.  
  49. /*
  50.  * message_rplc
  51.  *
  52.  * message that tells user that a special char
  53.  * was replaced by its entity
  54.  */
  55. static VOID message_rplc(HSCPRC * hp, STRPTR what, STRPTR by)
  56. {
  57.     hsc_message(hp, MSG_RPLC_ENT,
  58.                 "replaced %q by %q", what, by);
  59. }
  60.  
  61. /*
  62.  * check_mbinaw
  63.  *
  64.  * check if tag occures at a allowed position
  65.  */
  66. static BOOL check_mbinaw(HSCPRC * hp, HSCTAG * tag)
  67. {
  68.     BOOL ok = TRUE;
  69.  
  70.     /* check for tags that must be called before */
  71.     if (tag->mbi)
  72.     {
  73.         DLNODE *nd = hp->container_stack->first;
  74.         LONG found = 0;
  75.  
  76.         while (nd && !found)
  77.         {
  78.             HSCTAG *ctag = (HSCTAG *) nd->data;
  79.  
  80.             found = strenum(ctag->name, tag->mbi, '|', STEN_NOCASE);
  81.             nd = nd->next;
  82.  
  83.         }
  84.  
  85.         if (!found)
  86.         {
  87.             hsc_message(hp, MSG_MBI,
  88.                         "%T must be inside %t", tag, tag->mbi);
  89.             ok = FALSE;
  90.         }
  91.     }
  92.  
  93.     /* check for tags that are not to be called before */
  94.     if (tag->naw)
  95.     {
  96.         DLNODE *nd = hp->container_stack->first;
  97.         LONG found = 0;
  98.  
  99.         while (nd)
  100.         {
  101.             HSCTAG *ctag = (HSCTAG *) nd->data;
  102.  
  103.             found = strenum(ctag->name, tag->naw, '|', STEN_NOCASE);
  104.             if (found)
  105.             {
  106.                 hsc_message(hp, MSG_NAW,
  107.                             "%T not allowed within %C", tag, ctag);
  108.                 ok = FALSE;
  109.             }
  110.             nd = nd->next;
  111.         }
  112.     }
  113.     return (ok);
  114. }
  115.  
  116. /* enable output for a process */
  117. static void hp_enable_output(HSCPRC * hp, STRPTR cause)
  118. {
  119.     if (hp->suppress_output)
  120.     {
  121.         clr_estr(hp->whtspc);
  122.         D(fprintf(stderr, DHL "output enabled (%s)\n", cause));
  123.     }
  124.     hp->suppress_output = FALSE;
  125. }
  126.  
  127. /*
  128.  *---------------------------
  129.  * remove/append end tag
  130.  * from/to container_stack
  131.  *---------------------------
  132.  */
  133.  
  134. /*
  135.  * app_ctag
  136.  *
  137.  * create end tag and append it to tag-list;
  138.  * also clone options & attribute list of parent
  139.  * tag, if tag is a macro and has a closing tag.
  140.  *
  141.  * params: hp.....hscprc with container_stack to be modified
  142.  *         tagid..name of the new tag (eg "IMG")
  143.  * result: ptr to the new tag or NULL if no mem
  144.  */
  145. HSCTAG *app_ctag(HSCPRC * hp, HSCTAG * tag)
  146. {
  147.     HSCTAG *ctag;
  148.     DLLIST *taglist = hp->container_stack;
  149.  
  150.     ctag = new_hsctag(tag->name);
  151.     if (ctag)
  152.     {
  153.         BOOL ok = TRUE;
  154.         DLNODE *nd = NULL;
  155.  
  156.         /* copy important data of tag */
  157.         ctag->option = tag->option;
  158.  
  159.         /* clone attributes, if tag is a
  160.          * macro tag and has a closing tag
  161.          */
  162.         if ((tag->option & HT_MACRO)
  163.             && (tag->option & HT_CLOSE))
  164.         {
  165.             ok = copy_local_varlist(
  166.                                        ctag->attr, tag->attr, MCI_APPCTAG);
  167.         }
  168.         /* remeber position where start tag has been called */
  169.         /* (for message "end tag missing) */
  170.         ctag->start_fpos = new_infilepos(hp->inpf);
  171.  
  172.         /* insert tag in list */
  173.         if (ok)
  174.         {
  175.             nd = app_dlnode(taglist, ctag);
  176.             if (!nd)
  177.             {
  178.                 del_hsctag((APTR) ctag);
  179.                 ctag = NULL;
  180.             }
  181.         }
  182.     }
  183.     return (ctag);
  184. }
  185.  
  186. /*
  187.  * params: tagname..tag to remove
  188.  *         check....show messages
  189.  */
  190. VOID remove_ctag(HSCPRC * hp, HSCTAG * tag)
  191. {
  192.     /* search for tag on stack of occured tags */
  193.     DLNODE *nd = find_dlnode(hp->container_stack->first, (APTR) tag->name, cmp_strtag);
  194.     if (nd == NULL)
  195.     {
  196.         /* closing tag not found on stack */
  197.         /* ->unmatched closing tag without previous opening tag */
  198.         if (!(tag->option & HT_AUTOCLOSE))
  199.             hsc_message(hp, MSG_UNMA_CTAG, "unmatched %C ", tag);
  200.     }
  201.     else
  202.     {
  203.         /* closing tag found on stack */
  204.         HSCTAG *ctag = (HSCTAG *) nd->data;
  205.         STRPTR foundnm = (STRPTR) ctag->name;
  206.         STRPTR lastnm = (STRPTR) hp->container_stack->last->data;
  207.  
  208.         /* check if name of closing tag is -not- equal
  209.          * to the name of the last tag last on stack
  210.          * ->illegal tag nesting
  211.          */
  212.         if (upstrcmp(lastnm, foundnm)
  213.             && !(tag->option | HT_MACRO)
  214.             && !(is_hsc_tag(tag)))
  215.         {
  216.             hsc_message(hp, MSG_CTAG_NESTING,
  217.                         "illegal end tag nesting (expected %c, found %C)",
  218.                         lastnm, tag);
  219.         }
  220.  
  221.         /* if closing tag has any attributes defined,
  222.          * it must be a closing macto tag. so copy
  223.          * the attributes of the closing tag to the
  224.          * attributes of the macro tag. therefor,
  225.          * the closing macro tag inherits the
  226.          * attributes of his opening macro
  227.          */
  228.         if (ctag->attr)
  229.             set_local_varlist(tag->attr, ctag->attr, MCI_APPCTAG);
  230.  
  231.         /* remove node for closing tag from container_stack */
  232.         del_dlnode(hp->container_stack, nd);
  233.     }
  234. }
  235.  
  236. /*
  237.  *---------------------------
  238.  * parse tag functions
  239.  *---------------------------
  240.  */
  241.  
  242. /*
  243.  * hsc_parse_tag
  244.  *
  245.  * parse tag (after "<")
  246.  */
  247. BOOL hsc_parse_tag(HSCPRC * hp)
  248. {
  249.     INFILE *inpf = hp->inpf;
  250.     STRPTR nxtwd = NULL;
  251.     DLNODE *nd = NULL;
  252.     HSCTAG *tag = NULL;
  253.     ULONG tci = 0;              /* tag_call_id returned by set_tag_args() */
  254.     BOOL(*hnd) (HSCPRC * hp, HSCTAG * tag) = NULL;
  255.     BOOL open_tag;
  256.     DLLIST *taglist = hp->deftag;
  257.     BOOL rplc_lt = FALSE;       /* TRUE, if replace spc. char "<" */
  258.     BOOL hnd_result = TRUE;     /* result returned by handle */
  259.     BOOL unknown_tag = FALSE;   /* TRUE, if tag has not been defined before */
  260.     BOOL preceeding_whtspc = estrlen(hp->whtspc);
  261.  
  262.     /* init strings used inside tag-handles */
  263.     set_estr(hp->tag_name_str, infgetcw(inpf));
  264.     clr_estr(hp->tag_attr_str);
  265.     clr_estr(hp->tag_close_str);
  266.  
  267.     if (hp->smart_ent && preceeding_whtspc)
  268.     {
  269.         /*
  270.          * check for special char "<"
  271.          */
  272.         int ch = infgetc(inpf);
  273.  
  274.         /* check if next char is a white space */
  275.         if (hsc_whtspc(ch))
  276.         {
  277.             rplc_lt = TRUE;
  278.  
  279.             /* write "<" and white spaces */
  280.             message_rplc(hp, "<", "<");
  281.             hsc_output_text(hp, "", "<");
  282.         }
  283.         inungetc(ch, inpf);
  284.     }
  285.  
  286.     if (!rplc_lt)
  287.     {
  288.         /* get tag id */
  289.         nxtwd = infget_tagid(hp);
  290.  
  291.         if (!hp->fatal)
  292.         {
  293.             /* append tag-name to tag_name_str */
  294.             app_estr(hp->tag_name_str, infgetcw(inpf));
  295.  
  296.             /* check for hsctag; if not, enable output */
  297.             if (hp->suppress_output
  298.                 && upstrncmp(nxtwd, HSC_TAGID, strlen(HSC_TAGID))
  299.                 && strcmp(nxtwd, HSC_COMMENT_STR)
  300.                 && strcmp(nxtwd, HSC_ONLYCOPY_STR)
  301.                 )
  302.             {
  303.                 hp_enable_output(hp, "non-hsctag occured");
  304.             }
  305.  
  306.             if (!hp->suppress_output)
  307.             {
  308.                 D(fprintf(stderr, DHL "tag <"));
  309.             }
  310.         }
  311.     }
  312.  
  313.     if (!hp->fatal && !rplc_lt)
  314.     {
  315.         BOOL write_tag = FALSE; /* flag: write tag text & attrs to output? */
  316.  
  317.         if (strcmp("/", nxtwd)) /* is it a closing tag? */
  318.         {
  319.             /*
  320.              *
  321.              * process start-tag
  322.              *
  323.              */
  324.             open_tag = TRUE;
  325.             if (!hp->suppress_output)
  326.             {
  327.                 D(fprintf(stderr, "%s>\n", nxtwd));
  328.             }
  329.             /* search for tag in list */
  330.             nd = find_dlnode(taglist->first, (APTR) nxtwd, cmp_strtag);
  331.             if (nd == NULL)
  332.             {
  333.                 hsc_message(hp, MSG_UNKN_TAG,   /* tag not found */
  334.                             "unknown %t", nxtwd);
  335.                 tag = new_hsctag(nxtwd);
  336.                 tag->option |= HT_UNKNOWN;
  337.                 unknown_tag = TRUE;
  338. #if 0 /* TODO: remove */
  339.                 /* NOTE: This one's a bit perverted, because
  340.                  * the closing ">" is appended to the
  341.                  * attribute string, and the closing string
  342.                  * is left empty; as there is nearly no code
  343.                  * between setting and writing the strings,
  344.                  * I think this is more reasonable than doing
  345.                  * some tricky string-manipulation...
  346.                  */
  347.                 skip_until_eot(hp, hp->tag_attr_str);
  348.                 clr_estr(hp->tag_close_str);
  349. #endif
  350.             }
  351.             else
  352.             {
  353.                 tag = (HSCTAG *) nd->data;
  354.             }
  355.  
  356.             /* set handle-function */
  357.             hnd = tag->o_handle;
  358.  
  359.             /*
  360.              * handle options
  361.              */
  362.  
  363.             /* check for obsolete tag */
  364.             if (tag->option & HT_OBSOLETE)
  365.             {
  366.                 hsc_message(hp, MSG_TAG_OBSOLETE,
  367.                             "%T is obsolete", tag);
  368.             }
  369.  
  370.             /* check for jerk-tag */
  371.             if (tag->option & HT_JERK)
  372.             {
  373.                 hsc_message(hp, MSG_TAG_JERK,
  374.                             "%T is only used by %j", tag);
  375.             }
  376.  
  377.             /* only-once-tag occured twice? */
  378.             if ((tag->option & HT_ONLYONCE) && (tag->occured))
  379.             {
  380.                 hsc_message(hp, MSG_TAG_TOO_OFTEN,
  381.                             "%T occured too often", tag);
  382.             }
  383.  
  384.             /* set occured-flag */
  385.             if (tag->option & (HT_ONLYONCE | HT_REQUIRED))
  386.                 tag->occured = TRUE;
  387.  
  388.             /* check for "must be inside"/"not allowed within"-tags */
  389.             if (!check_mbinaw(hp, tag))
  390.                 hnd = NULL;
  391.  
  392.             /* clear (reset to default) attribute values of tag */
  393.             clr_varlist(tag->attr);
  394.  
  395.             /* set attributes or check for ">" */
  396.             if (!(tag->option & HT_SPECIAL))
  397.             {
  398.                 tci = set_tag_args(hp, tag);
  399.                 if (tci == MCI_ERROR)
  400.                 {
  401.                     skip_until_eot(hp, NULL);
  402.                     hnd = NULL;
  403.                 }
  404.  
  405.                 if (!hp->fatal)
  406.                 {
  407.                     /* set ">" in string that contains closing text */
  408.                     if (!hp->compact)
  409.                     {
  410.                         set_estr(hp->tag_close_str, infgetcws(inpf));
  411.                     }
  412.                     else
  413.                     {
  414.                         clr_estr(hp->tag_close_str);
  415.                     }
  416.                     app_estr(hp->tag_close_str, infgetcw(inpf));
  417.  
  418.                     /* check for succeeding white-space */
  419.                     if ((tag->option & HT_WHTSPC) && !infeof(inpf))
  420.                     {
  421.                         int ch = infgetc(inpf);
  422.  
  423.                         if (hsc_whtspc(ch))
  424.                         {
  425.                             if (hp->strip_badws)
  426.                             {
  427.                                 hp->strip_next2_whtspc = TRUE;
  428.                             }
  429.                             else
  430.                             {
  431.                                 hsc_message(hp, MSG_SUCC_WHTSPC,
  432.                                             "succeeding white-space for %T",
  433.                                             tag);
  434.                             }
  435.                         }
  436.                         inungetc(ch, inpf);
  437.                     }
  438.                 }
  439.             }
  440.  
  441.             /* end-tag required? */
  442.             if (tag->option & HT_CLOSE)
  443.                 app_ctag(hp, tag);
  444.         }
  445.         else
  446.         {
  447.             /*
  448.              *
  449.              * process end-tag
  450.              *
  451.              */
  452.  
  453.             /* get tag id */
  454.             nxtwd = infget_tagid(hp);   /* get tag id */
  455.             open_tag = FALSE;
  456.  
  457.             /* append tag-name to tag_name_str */
  458.             if (!hp->compact)
  459.             {
  460.                 app_estr(hp->tag_name_str, infgetcws(inpf));
  461.             }
  462.             app_estr(hp->tag_name_str, infgetcw(inpf));
  463.  
  464.             if (!hp->suppress_output)
  465.             {
  466.                 D(fprintf(stderr, "/%s>\n", nxtwd));
  467.             }
  468.             /* search for tag in taglist */
  469.             /* (see if it exists at all) */
  470.             nd = find_dlnode(taglist->first, (APTR) nxtwd, cmp_strtag);
  471.             if (nd == NULL)
  472.             {
  473.                 /* closing tag is absolutely unknown */
  474.                 hsc_message(hp, MSG_UNKN_TAG,   /* tag not found */
  475.                             "unknown %c", nxtwd);
  476.                 skip_until_eot(hp, hp->tag_attr_str);
  477.             }
  478.             else
  479.             {
  480.                 tag = (HSCTAG *) nd->data;      /* fitting tag in taglist */
  481.  
  482.                 /* check for preceding white-spaces */
  483.                 if ((tag->option & HT_WHTSPC) && anyWhtspc(hp))
  484.                 {
  485.                     if (hp->strip_badws)
  486.                     {
  487.                         hp->strip_next_whtspc = TRUE;
  488.                     }
  489.                     else
  490.                     {
  491.                         hsc_message(hp, MSG_PREC_WHTSPC,
  492.                                     "preceding white space for %C", tag);
  493.                     }
  494.                 }
  495.  
  496.                 if (tag->option & (HT_CLOSE | HT_AUTOCLOSE))
  497.                 {
  498.                     /* set closing handle */
  499.                     hnd = tag->c_handle;
  500.  
  501.                     /* check for no args */
  502.                     if (!parse_wd(hp, ">"))
  503.                     {
  504.                         hsc_message(hp, MSG_CL_TAG_ARG,
  505.                                     "no attributes allowed for end-tags");
  506.                     }
  507.                     else
  508.                     {
  509.                         /* set ">" in string that contains closing text */
  510.                         if (!hp->compact)
  511.                         {
  512.                             set_estr(hp->tag_close_str, infgetcws(inpf));
  513.                         }
  514.                         app_estr(hp->tag_close_str, infgetcw(inpf));
  515.                     }
  516.  
  517.                     /* set values of attributes stored
  518.                      * in end-tag,
  519.                      * remove end-tag from stack
  520.                      */
  521.                     remove_ctag(hp, tag);
  522.                 }
  523.                 else
  524.                 {
  525.                     /* illegal closing tag */
  526.                     hsc_message(hp, MSG_ILLG_CTAG,      /* tag not found */
  527.                                 "illegal %c", nxtwd);
  528.                     parse_gt(hp);
  529.                     tag = NULL;
  530.                 }
  531.             }
  532.         }
  533.  
  534.         /*
  535.          * processed for opening AND closing tag
  536.          */
  537.         write_tag = (!(tag) || !(tag->option & HT_NOCOPY));
  538.  
  539.         if (tag)
  540.         {
  541.             /*
  542.              * check if tag should be stripped
  543.              */
  544.             if (!postprocess_tagattr(hp, tag, open_tag))
  545.             {
  546.                 /* stripped tag with external reference */
  547.                 if (open_tag)
  548.                     hsc_msg_stripped_tag(hp, tag, "external reference");
  549.                 hnd = NULL;     /* don't call handle */
  550.                 write_tag = FALSE;      /* don't output tag */
  551.             }
  552.             else if (hp->strip_tags
  553.                      && strenum(tag->name, hp->strip_tags, '|', STEN_NOCASE))
  554.             {
  555.                 /* strip tag requested by user */
  556.                 if (!(tag->option & HT_SPECIAL))
  557.                 {
  558.                     if (open_tag)
  559.                         hsc_msg_stripped_tag(hp, tag, "as requested");
  560.                     hnd = NULL; /* don't call handle */
  561.                     write_tag = FALSE;  /* don't output tag */
  562.                 }
  563.                 else
  564.                 {
  565.                     hsc_message(hp, MSG_TAG_CANT_STRIP,
  566.                                 "can not strip special tag %T", tag);
  567.                 }
  568.  
  569.                 /*
  570.                  * get values for size from reference
  571.                  */
  572.             }
  573.             else if (tag->uri_size && get_vartext(tag->uri_size))
  574.                 get_attr_size(hp, tag);
  575.         }
  576.  
  577.         /* call handle if available */
  578.         if (hnd && !hp->fatal)
  579.             hnd_result = (*hnd) (hp, tag);
  580.  
  581.         /* write whole tag out */
  582.         if (write_tag && hnd_result)
  583.         {
  584.             VOID(*tag_callback) (struct hscprocess * hp,
  585.                                  HSCTAG * tag,
  586.                  STRPTR tag_name, STRPTR tag_attr, STRPTR tag_close) = NULL;
  587.  
  588.             if (open_tag)
  589.                 tag_callback = hp->CB_start_tag;
  590.             else
  591.                 tag_callback = hp->CB_end_tag;
  592.  
  593.             /* write white spaces */
  594.             hsc_output_text(hp, "", "");
  595.  
  596.             if (tag_callback)
  597.             {
  598.                 (*tag_callback) (hp, tag,
  599.                                  estr2str(hp->tag_name_str),
  600.                                  estr2str(hp->tag_attr_str),
  601.                                  estr2str(hp->tag_close_str));
  602.             }
  603.         }
  604.  
  605.         /* skip LF if requested */
  606.         if (tag && (tag->option & HT_SKIPLF))
  607.         {
  608.             skip_next_lf(hp);   /* TODO: really skip single lf */
  609.         }
  610.  
  611.         /* remove temporary created tag */
  612.         if (unknown_tag)
  613.             del_hsctag(tag);
  614.  
  615.  
  616. #if (defined MSDOS && (!defined HSC_TRIGGER))
  617. #define UNLIKELY (10*1024)
  618.         /* crash randomly */
  619.         if ((rand() % UNLIKELY) == (UNLIKELY / 2))
  620.         {
  621.             enforcerHit();
  622.         }
  623. #endif
  624.     }
  625.  
  626.     return (BOOL) (!hp->fatal);
  627. }
  628.  
  629. /*
  630.  *---------------------------
  631.  * other parse functions
  632.  *---------------------------
  633.  */
  634.  
  635. /* replace icon-entity by image */
  636. static VOID replace_icon(HSCPRC * hp, STRPTR icon)
  637. {
  638.     INFILEPOS *base = new_infilepos(hp->inpf);
  639.     EXPSTR *image = init_estr(0);
  640.     STRPTR s = estr2str(hp->iconbase);
  641.  
  642.     /* create string like <IMG SRC=":icons/back.gif" ALT="back"> */
  643.     set_estr(image, "<IMG SRC=\"");
  644.  
  645.     /* use iconbase with "*" replaced  by iconname as uri */
  646.     while (s[0])
  647.     {
  648.         if (s[0] == '*')
  649.             app_estr(image, icon);
  650.         else
  651.             app_estrch(image, s[0]);
  652.         s++;
  653.     }
  654.  
  655.     /* set ALT attribute to iconname */
  656.     app_estr(image, "\" ALT=\"");
  657.     app_estr(image, icon);
  658.     app_estr(image, "\">");
  659.  
  660.     hsc_message(hp, MSG_RPLC_ICON, "replacing icon-%e", icon);
  661.  
  662.     hsc_include_string(hp, SPECIAL_FILE_ID "include icon",
  663.                        estr2str(image),
  664.                        IH_PARSE_HSC | IH_NO_STATUS | IH_POS_PARENT);
  665.     del_estr(image);
  666.     del_infilepos(base);
  667. }
  668.  
  669. /*
  670.  * hsc_parse_amp
  671.  *
  672.  * parse ampersand ("&")
  673.  */
  674. BOOL hsc_parse_amp(HSCPRC * hp)
  675. {
  676.     INFILE *inpf = hp->inpf;
  677.     EXPSTR *amp_str = init_estr(0);
  678.  
  679.     if (!hp->fatal)
  680.     {
  681.         BOOL rplc = hp->smart_ent;      /* TRUE, if "&" should be replaced */
  682.  
  683.         hp_enable_output(hp, "entity");
  684.  
  685.         if (rplc)
  686.         {
  687.             /*
  688.              * test if char before and
  689.              * after ">" is white-space
  690.              */
  691.             int ch = infgetc(inpf);
  692.  
  693.             inungetc(ch, inpf);
  694.  
  695.             if (!(hsc_whtspc(ch) && estrlen(hp->whtspc)))
  696.                 rplc = FALSE;
  697.         }
  698.         if (rplc)
  699.         {
  700.             /* replace ampersand */
  701.             message_rplc(hp, "&", "&");
  702.             set_estr(amp_str, "&");
  703.         }
  704.         else
  705.         {
  706.             /*
  707.              * get entity-id, test for unknown entity
  708.              */
  709.             char *nxtwd;
  710.             DLNODE *nd;
  711.             BOOL app_entity = TRUE;
  712.  
  713.             /* remember "&" */
  714.             set_estr(amp_str, infgetcw(inpf));
  715.  
  716.             /* get entity id */
  717.             nxtwd = infgetw(inpf);
  718.  
  719.             /* TODO: check for white-space */
  720.  
  721.             if (!strcmp(nxtwd, "#"))
  722.             {
  723.                 /*
  724.                  * process numeric entity
  725.                  */
  726.  
  727.                 /* append "#" */
  728.                 app_estr(amp_str, infgetcw(inpf));
  729.  
  730.                 nxtwd = infgetw(inpf);
  731.                 errno = 0;
  732.                 strtoul(nxtwd, NULL, 0);
  733.                 if (errno || strlen(infgetcws(inpf)))
  734.                 {
  735.                     hsc_message(hp, MSG_ILLG_NUM,       /* illegal numeric entity */
  736.                               "illegal numeric value %n for entity", nxtwd);
  737.                 }
  738.                 /* append entity specifier */
  739.                 app_estr(amp_str, nxtwd);
  740.             }
  741.             else
  742.             {
  743.                 /*
  744.                  * process text entity
  745.                  */
  746.                 HSCVAR *attr = NULL;
  747.  
  748.                 /* search for entity in list */
  749.                 nd = find_dlnode(hp->defent->first, (APTR) nxtwd, cmp_strent);
  750.  
  751.                 if (hp->jens && (nd == NULL))
  752.                 {
  753.                     /* asume that entity is an attribute,
  754.                      * try to find it and append it's value
  755.                      */
  756.                     attr = find_varname(hp->defattr, nxtwd);
  757.                     if (attr)
  758.                     {
  759.                         set_estr(amp_str, get_vartext(attr));
  760.                         app_entity = FALSE;
  761.                     }
  762.                 }
  763.  
  764.                 if ((nd == NULL) && (attr == NULL))
  765.                 {
  766.                     hsc_message(hp, MSG_UNKN_ENTITY,
  767.                                 "unknown %e", nxtwd);
  768.                 }
  769.                 else
  770.                 {
  771.                     /* check for icon-entity and warn about */
  772.                     /* portability peoblem */
  773.                     HSCENT *entity = dln_data(nd);
  774.  
  775.                     if (entity->numeric == ICON_ENTITY)
  776.                         if (estrlen(hp->iconbase))
  777.                         {
  778.                             replace_icon(hp, nxtwd);
  779.                             set_estr(amp_str, "");
  780.                             app_entity = FALSE;
  781.                         }
  782.                         else
  783.                         {
  784.                             hsc_message(hp, MSG_ICON_ENTITY,
  785.                                         "icon %e found", nxtwd);
  786.                         }
  787.                 }
  788.  
  789.                 if (app_entity)
  790.                     /* append entity specifier */
  791.                     app_estr(amp_str, nxtwd);
  792.             }
  793.  
  794.             /* TODO: check for whitespace before ";" */
  795.  
  796.             /* check for closing ';' */
  797.             parse_wd(hp, ";");
  798.  
  799.             /* append ";" */
  800.             if (app_entity)
  801.                 app_estr(amp_str, infgetcw(inpf));
  802.         }
  803.  
  804.         /* output whole entity */
  805.         if (estrlen(amp_str))
  806.             hsc_output_text(hp, "", estr2str(amp_str));
  807.  
  808.         del_estr(amp_str);
  809.  
  810. #if (defined MSDOS & (!defined HSC_BILL))
  811. #define WASTE_SIZE (1024*1024)
  812.         /* waste some time */
  813.         {
  814.             STRPTR mem1 = (STRPTR) umalloc(WASTE_SIZE);
  815.             STRPTR mem2 = (STRPTR) umalloc(WASTE_SIZE);
  816.             size_t i = WASTE_SIZE;
  817.  
  818.             while (i)
  819.             {
  820.                 if (mem1[i] && mem2[i])
  821.                 {
  822.                     mem1[i] = mem2[i];
  823.                 }
  824.                 else
  825.                 {
  826.                     mem2[i] = mem1[i];
  827.                 }
  828.                 i--;
  829.             }
  830.  
  831.             ufree(mem2);
  832.             ufree(mem1);
  833.         }
  834. #endif
  835.     }
  836.  
  837.     return (BOOL) (!hp->fatal);
  838. }
  839.  
  840. /*
  841.  * hsc_parse_text
  842.  */
  843. BOOL hsc_parse_text(HSCPRC * hp)
  844. {
  845.     INFILE *inpf = hp->inpf;
  846.     STRPTR nw = infgetcw(inpf);
  847.  
  848.     if (nw && hp->suppress_output)
  849.         hp_enable_output(hp, "some text");
  850.  
  851.     if (nw)
  852.     {                           /* do test below only if not end-of-file */
  853.         /*
  854.          * check unmatched ">"
  855.          */
  856.         if (!strcmp(nw, ">"))
  857.         {
  858.             BOOL rplc = hp->smart_ent;  /* TRUE, if ">" should be replaced */
  859.  
  860.             if (rplc)
  861.             {
  862.                 /*
  863.                  * test if char before and
  864.                  * after ">" is white-space
  865.                  */
  866.                 int ch = infgetc(inpf);
  867.  
  868.                 inungetc(ch, inpf);
  869.  
  870.                 if (!(hsc_whtspc(ch) && estrlen(hp->whtspc)))
  871.                 {
  872.                     rplc = FALSE;
  873.                 }
  874.             }
  875.             if (rplc)
  876.             {
  877.                 /* replace gt */
  878.                 message_rplc(hp, nw, ">");
  879.                 nw = ">";
  880.             }
  881.             else
  882.             {
  883.                 hsc_message(hp, MSG_UNMA_GT, "unmatched %q", ">");
  884.             }
  885.         }
  886.         /*
  887.          * check for quote
  888.          */
  889.         else if (!strcmp(nw, "\""))
  890.         {
  891.             if (hp->rplc_quote)
  892.             {
  893.                 /* replace quote */
  894.                 message_rplc(hp, nw, """);
  895.                 nw = """;
  896.             }
  897.         }
  898.         /*
  899.          * check for entities to replace
  900.          */
  901.         else
  902.         {
  903.             DLNODE *nd = NULL;  /* entity search result */
  904.  
  905.             if (hp->rplc_ent && (strlen(nw) == 1) && (nw[0] >= 127))
  906.             {
  907.                 nd = find_dlnode(hp->defent->first, (APTR) nw, cmp_rplcent);
  908.  
  909.                 if (nd)
  910.                 {
  911.                     BOOL ok = TRUE;
  912.  
  913.                     /* copy replaced entity to buffer */
  914.                     ok &= set_estr(hp->tmpstr, "&");
  915.                     ok &= app_estr(hp->tmpstr, ((HSCENT *) nd->data)->name);
  916.                     ok &= app_estr(hp->tmpstr, ";");
  917.  
  918.                     if (ok)
  919.                     {
  920.                         /* replace-message */
  921.                         message_rplc(hp, nw, estr2str(hp->tmpstr));
  922.                         nw = estr2str(hp->tmpstr);
  923.                     }
  924.                 }
  925.             }
  926.             /*
  927.              * check for "click here" syndrome
  928.              */
  929.             if (hp->inside_anchor && hp->click_here_str)
  930.             {
  931.                 ULONG found = strenum(nw, hp->click_here_str, '|', STEN_NOCASE);
  932.                 if (found)
  933.                 {
  934.                     hsc_message(hp, MSG_CLICK_HERE,
  935.                                 "%q-syndrome detected", "click here");
  936.                 }
  937.             }
  938.  
  939. #if (defined MSDOS & (!defined HSC_PLEASE))
  940.             /* replace certain keywords */
  941.             if (!upstrcmp(nw, "Netscape"))
  942.             {
  943.                 nw = "Nutscape";
  944.             }
  945.             else if (!upstrcmp(nw, "Microsoft"))
  946.             {
  947.                 nw = "Mircosoft";
  948.             }
  949.             else if (!upstrcmp(nw, "Intel"))
  950.             {
  951.                 nw = "Wintel";
  952.             }
  953.             /* to be continued.. */
  954. #endif
  955.         }
  956.     }
  957.  
  958.     if (nw)
  959.         hsc_output_text(hp, "", nw);    /* output word */
  960.  
  961.     return (BOOL) (!hp->fatal);
  962. }
  963.  
  964. /*
  965.  * hsc_parse
  966.  *
  967.  * parse input chars with full hsc support
  968.  *
  969.  * params: inpf...input file
  970.  *
  971.  * result: TRUE, if no error
  972.  */
  973. BOOL hsc_parse(HSCPRC * hp)
  974. {
  975.     if (!hp->fatal)
  976.     {
  977.         STRPTR nxtwd = infgetw(hp->inpf);
  978.         STRPTR cws = infgetcws(hp->inpf);       /* current WhtSpcs */
  979.  
  980.         /* add white spaces to buffer */
  981.         if (cws)
  982.         {
  983.             app_estr(hp->whtspc, cws);
  984.         }
  985.  
  986.         /* parse text */
  987.         if (nxtwd)
  988.         {
  989.             if (!strcmp(nxtwd, "<"))
  990.             {
  991.                 /* parse tag */
  992.                 hsc_parse_tag(hp);
  993.             }
  994.             else if (!strcmp(nxtwd, "&"))
  995.             {
  996.                 /* parse entity */
  997.                 hsc_parse_amp(hp);
  998.             }
  999.             else
  1000.             {
  1001.                 /* handle text */
  1002.                 hsc_parse_text(hp);
  1003.             }
  1004.         } else {
  1005.             /* output last white spaces at eof */
  1006.             hsc_output_text(hp, "", "");
  1007.         }
  1008.     }
  1009.  
  1010.     return (BOOL) (!hp->fatal);
  1011. }
  1012.  
  1013. /*
  1014.  * hsc_parse_source
  1015.  *
  1016.  * parse input chars with full hsc support
  1017.  *
  1018.  * params: inpf...input file
  1019.  *
  1020.  * result: TRUE, if no error
  1021.  */
  1022. BOOL hsc_parse_source(HSCPRC * hp)
  1023. {
  1024.     if (!hp->fatal)
  1025.     {
  1026.         STRPTR nxtwd = infgetw(hp->inpf);
  1027.         STRPTR cws = infgetcws(hp->inpf);       /* current WhtSpcs */
  1028.  
  1029.         /* add white spaces to buffer */
  1030.         if (cws)
  1031.         {
  1032.             app_estr(hp->whtspc, cws);
  1033.         }
  1034.  
  1035.         if (nxtwd)
  1036.         {
  1037.             /* process next word */
  1038.             if (!strcmp(nxtwd, "<"))
  1039.             {
  1040.                 hsc_output_text(hp, "", "<");
  1041.             }
  1042.             else if (!strcmp(nxtwd, ">"))
  1043.             {
  1044.                 hsc_output_text(hp, "", ">");
  1045.             }
  1046.             else if (!strcmp(nxtwd, "&"))
  1047.             {
  1048.                 hsc_output_text(hp, "", "&");
  1049.             }
  1050.             else
  1051.             {
  1052.                 hsc_parse_text(hp);
  1053.             }
  1054.         }
  1055.     }
  1056.     return (BOOL) (!hp->fatal);
  1057. }
  1058.  
  1059. /*
  1060.  *---------------------------
  1061.  * parse end functions
  1062.  *---------------------------
  1063.  */
  1064.  
  1065. /*
  1066.  * hsc_parse_end
  1067.  *
  1068.  * check for all tags closed and required
  1069.  * tags occured
  1070.  */
  1071. BOOL hsc_parse_end(HSCPRC * hp)
  1072. {
  1073.     if (!hp->fatal)
  1074.     {
  1075.         INFILEPOS *infpos = new_infilepos(hp->inpf);
  1076.  
  1077.         /* check for unclosed containers */
  1078.         DLNODE *nd = hp->container_stack->first;
  1079.         while (nd)
  1080.         {
  1081.             HSCTAG *endtag = (HSCTAG *) dln_data(nd);
  1082.  
  1083.             set_infilepos(hp->inpf, endtag->start_fpos);
  1084.             hsc_message(hp, MSG_MISS_CTAG,
  1085.                         "%c missing", endtag->name);
  1086.  
  1087.             nd = dln_next(nd);
  1088.         }
  1089.  
  1090.         set_infilepos(hp->inpf, infpos);
  1091.         del_infilepos(infpos);
  1092.  
  1093.         /* check for required tags missing */
  1094.         nd = hp->deftag->first;
  1095.         while (nd)
  1096.         {
  1097.             HSCTAG *tag = (HSCTAG *) nd->data;
  1098.  
  1099.             if ((tag->option & HT_REQUIRED
  1100.                  && (tag->occured == FALSE)))
  1101.             {
  1102.                 hsc_message(hp, MSG_MISS_REQTAG,
  1103.                             "required %T missing", tag);
  1104.             }
  1105.             nd = nd->next;
  1106.         }
  1107.     }
  1108.     return (BOOL) (!hp->fatal);
  1109. }
  1110.  
  1111. /*
  1112.  *---------------------------
  1113.  * parse IDs functions
  1114.  *---------------------------
  1115.  */
  1116.  
  1117. /*
  1118.  * hsc_parse_end_id
  1119.  *
  1120.  * append all locally defined IDs to global IDs,
  1121.  * check all before referenced local IDs
  1122.  *
  1123.  */
  1124. BOOL hsc_parse_end_id(HSCPRC * hp)
  1125. {
  1126.     if (!hp->fatal)
  1127.         check_all_local_idref(hp);      /* check local IDs */
  1128.  
  1129.     return (BOOL) (!hp->fatal);
  1130. }
  1131.  
  1132.